﻿using System;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;


namespace CSharp.Libs.Misc
{

    /// <summary>LocalApplicationOptions</summary>
    /// <history> created 14.02.2010 VB</history>
    /// <history>modified 10.04.2011 VB: added _SetComment()</history>
    /// <history>modified 29.04.2011 VB: added OptionsChanged event</history>
    /// <history>modified 19.02.2012 VB: added possibility to pass a desired FileName to constructor</history>
    public class LocalApplicationOptions
    {
        #region declarations
        // object reference pointers
        //private cExceptionCollector m_EC = null;//Errorhandler

        private String m_strExecutableFullName = Assembly.GetExecutingAssembly().Location;
        private String m_strExecutablePath = "";
        private String m_strOptionsFileFullName = "";

        private Boolean _fThrowOptionsChangedEvent = true;

        //XML References
        private XDocument m_xdOptions = null;

        #region     constants
        public const String ELEMENT_NAME_ROOT = "Options";
        #endregion

        #region     events
        public delegate void OptionsChangedEventHandler(object sender);
        public event OptionsChangedEventHandler OptionsChanged;
        private void ThrowOptionsChangedEvent()
        {
            if (OptionsChanged != null)
            {
                OptionsChanged(this);
            }
        }
        #endregion
        #endregion



        #region constructor destructor
        public LocalApplicationOptions()
        {
            //Get FileName and Path of Current Executable
            m_strExecutablePath = new FileInfo(m_strExecutableFullName).DirectoryName;
            m_strOptionsFileFullName = String.Concat(m_strExecutableFullName, ".options");

            //Initialize Optionsfile
            m_InitializeOptions();
        }

        public LocalApplicationOptions(
            String FileName)
        {
            //Get FileName and Path of Current Executable
            m_strExecutablePath = new FileInfo(m_strExecutableFullName).DirectoryName;
            m_strOptionsFileFullName = String.Concat(m_strExecutablePath, "\\", FileName);

            //Initialize Optionsfile
            m_InitializeOptions();
        }
        #endregion



        #region private functions
        /// <summary>m_InitializeOptions
        /// </summary>
        /// <history> created  14.02.2010 VB</history>
        private void m_InitializeOptions()
        {
            try
            {
                if (!File.Exists(m_strOptionsFileFullName))
                {
                    //File does not exist -> create basic file
                    m_CreateBasicOptionsFile();
                }
                else
                {
                    //File exists -> check version?
                }

                m_xdOptions = XDocument.Load(m_strOptionsFileFullName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>m_CreateBasicOptionsFile
        /// </summary>
        /// <history> created  14.02.2010 VB</history>
        private void m_CreateBasicOptionsFile()
        {
            try
            {
                //Create Document Object and initial XMLWriter
                XmlDocument xmlDoc = new XmlDocument();
                XmlTextWriter xmlWriter = new XmlTextWriter(
                    m_strOptionsFileFullName, 
                    System.Text.Encoding.UTF8);
                xmlWriter.Formatting = Formatting.Indented;

                //Create Header
                xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
                xmlWriter.WriteStartElement(ELEMENT_NAME_ROOT);
                xmlWriter.Close();

                xmlWriter = null;
                xmlDoc = null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>m_GetOption
        /// </summary>
        /// <param name="OptionName"></param>
        /// <returns></returns>
        /// <history> created  14.02.2010 VB</history>
        private String m_GetOption(
            String OptionName)
        {
            try
            {
                XElement xeOption = m_xdOptions.Root.Element(OptionName);
                
                if (xeOption != null)
                {
                    return xeOption.Value;
                }

                return "";
            }
            catch (Exception ex)
            {
                return "";
                throw ex;
            }
        }

        /// <summary>m_SetOption
        /// </summary>
        /// <param name="OptionName"></param>
        /// <param name="OptionValue"></param>
        /// <history> created  14.02.2010 VB</history>
        private void m_SetOption(
            String OptionName,
            String OptionValue)
        {
            try
            {
                XElement xeOption = m_xdOptions.Root.Element(OptionName);
                
                if (xeOption == null)
                {
                    xeOption = new XElement(OptionName);
                    m_xdOptions.Root.Add(xeOption);
                }

                xeOption.Value = OptionValue;

                m_xdOptions.Save(m_strOptionsFileFullName);

                if (_fThrowOptionsChangedEvent)
                {
                    ThrowOptionsChangedEvent();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>m_SetOption2</summary>
        /// <param name="OptionName"></param>
        /// <param name="OptionValue"></param>
        /// <history> created  17.05.2011 VB</history>
        private void m_SetOption2(
            String OptionName,
            String OptionValue)
        {
            try
            {
                Boolean fFoundOption = false;

                foreach (XElement xeOption in m_xdOptions.Root.Elements())
                {
                    if (xeOption.Name.LocalName == OptionName)
                    {
                        fFoundOption = true;

                        xeOption.Value = OptionValue;

                        break;
                    }
                }
                
                if (!fFoundOption)
                {
                    XElement xeOption = new XElement(OptionName);
                    m_xdOptions.Root.Add(xeOption);
                    xeOption.Value = OptionValue;
                }

                m_xdOptions.Save(m_strOptionsFileFullName);

                if (_fThrowOptionsChangedEvent)
                {
                    ThrowOptionsChangedEvent();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>m_GetOption
        /// </summary>
        /// <param name="OptionName"></param>
        /// <returns></returns>
        /// <history> created  14.02.2010 VB</history>
        private XElement m_GetOptionXElement(
            String OptionName)
        {
            try
            {
                XElement xeOption = m_xdOptions.Root.Element(OptionName);

                if (xeOption != null)
                {
                    return xeOption;
                }

                return null;
            }
            catch (Exception ex)
            {
                return null;
                throw ex;
            }
        }

        /// <summary>m_SetOption
        /// </summary>
        /// <param name="OptionName"></param>
        /// <param name="OptionValue"></param>
        /// <history> created  14.02.2010 VB</history>
        private void m_SetOptionXElement(
            XElement OptionElement)
        {
            try
            {
                XElement xeOption = m_xdOptions.Root.Element(OptionElement.Name);

                if (xeOption == null)
                {
                    m_xdOptions.Root.Add(OptionElement);
                }
                else
                {
                    m_xdOptions.Root.Element(OptionElement.Name).Remove();
                    //xeOption  = OptionElement;
                    m_xdOptions.Root.Add(OptionElement);
                }

                m_xdOptions.Save(m_strOptionsFileFullName);

                if (_fThrowOptionsChangedEvent)
                {
                    ThrowOptionsChangedEvent();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>_SetComment
        /// 
        /// </summary>
        /// <param name="Comment">Comment to append</param>
        /// <history> created  10.04.2011 VB</history>
        private void _SetComment(
            String Comment)
        {
            try
            {
                XComment xcComment = new XComment(Comment);

                m_xdOptions.Root.Add(xcComment);

                m_xdOptions.Save(m_strOptionsFileFullName);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }
        #endregion



        #region interface
        #region     methods
        public String GetOption(
            String OptionName)
        {
            return m_GetOption(OptionName);
        }

        public void SetOption(
            String OptionName,
            String OptionValue)
        {
            m_SetOption(OptionName, OptionValue);
        }

        public void SetOption2(
            String OptionName,
            String OptionValue)
        {
            m_SetOption2(OptionName, OptionValue);
        }

        public XElement GetOptionXElement(
            String OptionName)
        {
            return m_GetOptionXElement(OptionName);
        }

        public void SetOptionXElement(
            XElement OptionElement)
        {
            m_SetOptionXElement(OptionElement);
        }

        public void SetComment(
            String Comment)
        {
            _SetComment(Comment);
        }
        #endregion

        #region     properties
        public String ExecutableFullName
        {
            get
            {
                return m_strExecutableFullName;
            }
        }

        public String ExecutablePath
        {
            get
            {
                return m_strExecutablePath;
            }
        }

        public String OptionsFileFullName
        {
            get
            {
                return m_strOptionsFileFullName;
            }
        }

        public Int32 OptionsCount
        {
            get
            {
                Int32 Count = 0;

                foreach (XElement XE in m_xdOptions.Elements(ELEMENT_NAME_ROOT).Elements())
                {
                    Count++;
                }

                return Count;//Options-Basisknoten rausrechnen
            }
        }

        public Boolean DoThrowOptionsChangedEvent
        {
            get
            {
                return _fThrowOptionsChangedEvent;
            }
            set
            {
                _fThrowOptionsChangedEvent = value;
            }
        }
        #endregion
        #endregion
    }
}
